﻿using FastMvc.Auth;
using FastMvc.Crud;
using FastMvc.Crud.Models;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace FastMvc.Repositories
{
    /// <summary>
    /// 使用SqlSugar实现的仓库
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <typeparam name="TPrimaryKey"></typeparam>
    public class SqlSugarRepository<TEntity, TPrimaryKey> : IRepository<TEntity, TPrimaryKey>
        where TEntity : DBEntity<TPrimaryKey>, new()
    {
        protected SqlSugar.SqlSugarClient DB
        {
            get
            {
                var db = DBHelper.SqlSugarDB;
                if (!IgnoreGloableFilters && UserAuth != null)
                {
                    db.QueryFilter.Add(new SqlSugar.SqlFilterItem()
                    {
                        FilterValue = filterDb =>
                        {
                            return new SqlFilterResult() { Sql = " iDelete=0" };
                        },
                        IsJoinQuery = false
                    });

                    if (!string.IsNullOrEmpty(UserAuth.sOrgId))
                    {
                        db.QueryFilter.Add(new SqlSugar.SqlFilterItem()
                        {
                            FilterValue = filterDb =>
                            {
                                return new SqlFilterResult() { Sql = " sOrgId=@gloablOrgId", Parameters = new { gloablOrgId = UserAuth.sOrgId } };
                            },
                            IsJoinQuery = false
                        });
                    }
                }
                return db;
            }
        }

        public UserAuthInfo UserAuth { get; set; }

        /// <summary>
        /// 忽略公共Filter
        /// </summary>
        private bool IgnoreGloableFilters { get; set; } = false;

        public SqlSugarRepository<TEntity, TPrimaryKey> IgnorGlobalFilters()
        {
            //this.IgnoreGloableFilters = true;
            //return this;

            SqlSugarRepository<TEntity, TPrimaryKey> re = this.MemberwiseClone() as SqlSugarRepository<TEntity, TPrimaryKey>;
            re.IgnoreGloableFilters = true;
            return re;
        }

        public virtual bool Any()
        {
            return DB.Queryable<TEntity>().Any();
        }

        public virtual bool Any(Expression<Func<TEntity, bool>> expression)
        {
            return DB.Queryable<TEntity>().Any(expression);
        }

        public virtual async Task<bool> AnyAsync()
        {
            return await DB.Queryable<TEntity>().AnyAsync();
        }

        public virtual async Task<bool> AnyAsync(Expression<Func<TEntity, bool>> expression)
        {
            return await DB.Queryable<TEntity>().AnyAsync(expression);
        }

        public virtual int Count()
        {
            return DB.Queryable<TEntity>().Count();
        }

        public virtual int Count(Expression<Func<TEntity, bool>> expression)
        {
            return DB.Queryable<TEntity>().Count(expression);
        }

        public virtual async Task<int> CountAsync()
        {
            return await DB.Queryable<TEntity>().CountAsync();
        }

        public virtual async Task<int> CountAsync(Expression<Func<TEntity, bool>> expression)
        {
            return await DB.Queryable<TEntity>().CountAsync(expression);
        }

        public virtual void Delete(TEntity entity)
        {
            DB.Deleteable<TEntity>(entity).ExecuteCommand();
        }

        public virtual void Delete(TPrimaryKey id)
        {
            DB.Updateable<TEntity>().SetColumns(t => t.iDelete == 1).Where($"sId=@sId", new { sId = id }).ExecuteCommand();
        }

        public virtual void Delete(Expression<Func<TEntity, bool>> expression)
        {
            DB.Updateable<TEntity>().SetColumns(t => t.iDelete == 1).Where(expression).ExecuteCommand();
        }

        public virtual async Task DeleteAsync(TEntity entity)
        {
            await DB.Updateable<TEntity>().SetColumns(t => t.iDelete == 1).Where(t => t.sId.Equals(entity.sId)).ExecuteCommandAsync();
        }

        public virtual async Task DeleteAsync(TPrimaryKey id)
        {
            await DB.Updateable<TEntity>().SetColumns(t => t.iDelete == 1).Where(t =>t.sId.Equals(id)).ExecuteCommandAsync();
        }

        public virtual async Task DeleteAsync(Expression<Func<TEntity, bool>> expression)
        {
            await DB.Updateable<TEntity>().SetColumns(t => t.iDelete == 1).Where(expression).ExecuteCommandAsync();
        }

        public virtual TEntity FirstOrDefault(Expression<Func<TEntity, bool>> expression)
        {
            return DB.Queryable<TEntity>().Where(expression).First();
        }

        public virtual async Task<TEntity> FirstOrDefaultAsync(Expression<Func<TEntity, bool>> expression)
        {
            return await DB.Queryable<TEntity>().Where(expression).FirstAsync();
        }

        public virtual TEntity Get(TPrimaryKey sId)
        {
            return DB.Queryable<TEntity>().Where(t => t.sId.Equals(sId)).First();
        }

        public virtual IEnumerable<TEntity> GetAll()
        {
            return DB.Queryable<TEntity>().ToList();
        }

        public virtual async Task<IEnumerable<TEntity>> GetAllAsync()
        {
            return await DB.Queryable<TEntity>().ToListAsync();
        }

        public virtual IEnumerable<TEntity> GetAll(Expression<Func<TEntity, bool>> expression)
        {
            return DB.Queryable<TEntity>().Where(expression).ToList();
        }

        public virtual async Task<IEnumerable<TEntity>> GetAllAsync(Expression<Func<TEntity, bool>> expression)
        {
            return await DB.Queryable<TEntity>().Where(expression).ToListAsync();
        }

        public virtual async Task<TEntity> GetAsync(TPrimaryKey sId)
        {
            return await DB.Queryable<TEntity>().Where(t=>t.sId.Equals(sId)).FirstAsync();
        }

        public virtual TEntity Insert(TEntity entity)
        {
            return DB.Insertable(entity).ExecuteReturnEntity();
        }

        public virtual async Task<TEntity> InsertAsync(TEntity entity)
        {
            return await DB.Insertable(entity).ExecuteReturnEntityAsync();
        }

        public virtual async Task<TPrimaryKey> InsertRetrunIdAsync(TEntity entity)
        {
            entity = await InsertAsync(entity);
            return entity.sId;
        }

        public virtual TPrimaryKey InsertReturnId(TEntity entity)
        {
            return Insert(entity).sId;
        }

        public virtual TEntity Single(Expression<Func<TEntity, bool>> expression)
        {
            return DB.Queryable<TEntity>().Where(expression).Single();
        }

        public virtual async Task<TEntity> SingleAsync(Expression<Func<TEntity, bool>> expression)
        {
            return await DB.Queryable<TEntity>().Where(expression).SingleAsync();
        }

        public virtual void Update(TEntity entity)
        {
            entity.dUpdateTime = DateTime.Now;

            DB.Updateable<TEntity>().ExecuteCommand();
        }

        public virtual async Task UpdateAsync(TEntity entity)
        {
            entity.dUpdateTime = DateTime.Now;

            await DB.Updateable<TEntity>().ExecuteCommandAsync();
        }

        public void RunTrans(Action<IRepository<TEntity, TPrimaryKey>> iAct)
        {
            try
            {
                DB.BeginTran();
                iAct.Invoke(this);
                DB.CommitTran();
            }
            catch (Exception)
            {
                DB.RollbackTran();
                throw;
            }
        }

        public async Task RunTransAsync(Action<IRepository<TEntity, TPrimaryKey>> iAct)
        {
            try
            {
                await Task.Factory.StartNew(() =>
                {
                    DB.BeginTran();
                    iAct.Invoke(this);
                    DB.CommitTran();
                });
            }
            catch (Exception ex)
            {
                DB.RollbackTran();
                await Task.FromException(ex);
            }
        }
    }

    public class SqlSugarMVCRepository<TEntity> : SqlSugarRepository<TEntity, string>, IRepository<TEntity>
        where TEntity : DBEntity<string>, new()
    {

    }
    /* 
    // 多表联合仓储？？
    public class FastMVCRepository<TEntity, TPrimaryKey, T2> : SqlSugarRepository<TEntity, TPrimaryKey>, IRepository<TEntity, TPrimaryKey, T2>
        where TEntity : DBEntity<TPrimaryKey>, new()
        where T2 : class, new()
    {
        public IEnumerable<KeyValuePair<TEntity, T2>> JoinQuery(DBJoinType joinType, Expression<Func<TEntity, T2, bool>> joinExpress, Expression<Func<TEntity, T2, bool>> whereExpress)
        {
            SqlSugar.JoinType jt = (SqlSugar.JoinType)(int)joinType;
            var query = this.DB.Queryable<TEntity, T2>(DB.Queryable<TEntity>(), DB.Queryable<T2>(), jt, joinExpress);
            query = query
                .Where(whereExpress);

            var list = query.Select("t.sId, OrgCode, sOrgId,sMenuId").ToList();
            return null;
        }
    }
    */
}
